using System;
using BoxBinary.AspectCache.Core.ConfigurationMappers;

namespace BoxBinary.AspectCache.Core.CacheManagement
{
    /// <summary>
    /// Acts as a wrapper to allow third-party or native types to be cached as if they implemented <see cref="ICacheable"/>.
    /// </summary>
    [Serializable]
    public class CacheItemWrapper : ICacheable
    {
        private readonly object _objectToCache;
        private readonly CacheKeyParamsCollection _uniqueIdentifiers;
        private string _cachePolicy = "default";
        private string _objectTypeName = string.Empty;

        /// <summary>
        /// Populates the wrapper from the given object to cache, together with the <paramref name="uniqueIdentifiers"/> for establishing the cache key.
        /// Uses the default <see cref="CachePolicySpecification"/>.
        /// </summary>
        /// <param name="objectToCache">Object that will be cached</param>
        /// <param name="uniqueIdentifiers">Strings for establishing the cache key</param>
        public CacheItemWrapper(object objectToCache, CacheKeyParamsCollection uniqueIdentifiers)
        {
            #region Validate

            if (objectToCache == null || uniqueIdentifiers == null)
                throw new ArgumentNullException(objectToCache == null ? "objectToCache" : "uniqueIdentifiers");
            if (uniqueIdentifiers.Count == 0)
            {
                throw new ArgumentOutOfRangeException("uniqueIdentifiers", uniqueIdentifiers.Count,
                                                      "Must have a Count greater than 0");
            }

            #endregion

            _uniqueIdentifiers = uniqueIdentifiers;
            _objectTypeName = objectToCache.GetType().FullName;
            _objectToCache = objectToCache;
        }

        /// <summary>
        /// Populates the wrapper from the given object to cache, together with the <paramref name="uniqueIdentifiers"/> for establishing the cache key and
        /// the supplied cache category key.
        /// </summary>
        /// <param name="objectToCache">Object that will be cached</param>
        /// <param name="uniqueIdentifiers">Strings for establishing the cache key</param>
        /// <param name="cachePolicy">Key with which a <see cref="CachePolicySpecification"/> will be looked-up from the application's caching configuration file</param>
        public CacheItemWrapper(object objectToCache, CacheKeyParamsCollection uniqueIdentifiers, string cachePolicy)
            : this(objectToCache, uniqueIdentifiers)
        {
            #region Validate

            if (string.IsNullOrEmpty(cachePolicy))
                throw new ArgumentException("Must not be blank", "cachePolicy");

            #endregion

            _cachePolicy = cachePolicy;
        }

        /// <summary>
        /// Object that will be cached
        /// </summary>
        public object Item
        {
            get { return _objectToCache; }
        }

        #region ICacheable Members

        /// <summary>
        /// <see cref="CacheKeyParamsCollection"/> containing strings used to establish the cache key. Typically contains instance-specific
        /// values such as a content ID to differentiate two cache entries of the same object type.
        /// </summary>
        public CacheKeyParamsCollection CacheKeyUniqueParams
        {
            get { return _uniqueIdentifiers; }
        }

        /// <summary>
        /// Key with which a <see cref="CachePolicySpecification"/> will be looked-up from the application's caching configuration file
        /// </summary>
        public string CachePolicy
        {
            get { return _cachePolicy; }
            set { _cachePolicy = value; }
        }

        #endregion
    }
}